﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Timers;
using HighPerformanceLog.V2;

namespace ProcessBarDemo.UpdateFramework
{
    public class VersionCheckedEventArgs : EventArgs
    {
        public bool HasUpdate { get; set; }
        public string? CurrentVersion { get; set; }
        public string? NewVersion { get; set; }
        public string? UpdateFileUrl { get; set; }
        public string? UpdateMessage { get; set; }
    }

    public class UpdateChecker
    {
        private readonly string updateFilePath;
        private readonly string localIniPath;
        private readonly string remoteIniUrl;
        private readonly System.Timers.Timer timer;
        private readonly HttpClient client = new HttpClient();

        public event EventHandler<VersionCheckedEventArgs>? VersionChecked;

        public UpdateChecker(string localIniPath, string remoteIniUrl, string updateFilePath, double intervalMs)
        {
            this.localIniPath = localIniPath;
            this.remoteIniUrl = remoteIniUrl;
            this.updateFilePath = updateFilePath;

            timer = new System.Timers.Timer(intervalMs);
            timer.Elapsed += (s, e) => CheckForUpdate();
            timer.AutoReset = true;
        }

        public void Start()
        {
            CheckForUpdate();
            timer.Start();
        }
        public void Stop() => timer.Stop();

        public void CheckForUpdate()
        {
            try
            {
                var localConfig = ReadIniFile(localIniPath);
                string? localVersion = localConfig.GetValueOrDefault("TargetProgram.VersionName");

                string remoteContent = DownloadStringSync(remoteIniUrl);
                var remoteConfig = ParseIniFromString(remoteContent);
                string? remoteVersion = remoteConfig.GetValueOrDefault("TargetProgram.VersionName");
                string? firstUrl = remoteConfig.GetValueOrDefault("ServerSetting.FirstUrl");

                if (string.IsNullOrEmpty(remoteVersion) || string.IsNullOrEmpty(firstUrl))
                {
                    OnVersionChecked(new VersionCheckedEventArgs
                    {
                        HasUpdate = false,
                        CurrentVersion = localVersion,
                        NewVersion = remoteVersion,
                        UpdateMessage = "远程配置缺少 VersionName 或 FirstUrl"
                    });
                    return;
                }

                if (remoteVersion != localVersion)
                {
                    string updateUrl = $"{firstUrl}{remoteVersion}/update_files.xml";

                    byte[] updateData = DownloadBytesSync(updateUrl);
                    File.WriteAllBytes(updateFilePath, updateData);

                    byte[] iniData = DownloadBytesSync(remoteIniUrl);
                    File.WriteAllBytes(localIniPath, iniData);

                    OnVersionChecked(new VersionCheckedEventArgs
                    {
                        HasUpdate = true,
                        CurrentVersion = localVersion,
                        NewVersion = remoteVersion,
                        UpdateFileUrl = updateUrl,
                        UpdateMessage = "发现新版本，已下载 update_files.xml 和 system.ini"
                    });
                }
                else
                {
                    OnVersionChecked(new VersionCheckedEventArgs
                    {
                        HasUpdate = false,
                        CurrentVersion = localVersion,
                        NewVersion = remoteVersion,
                        UpdateMessage = "版本未变"
                    });
                }
            }
            catch (Exception ex)
            {
                HWLogger.ErrorLog($"检测更新失败：{ex.Message}");
                OnVersionChecked(new VersionCheckedEventArgs
                {
                    HasUpdate = false,
                    UpdateMessage = $"更新检查失败: {ex.Message}"
                });
            }
        }

        public bool CheckAndDownloadIfMissing(string exePath)
        {
            if (File.Exists(exePath))
                return true;

            try
            {
                string remoteContent = DownloadStringSync(remoteIniUrl);
                var remoteConfig = ParseIniFromString(remoteContent);
                string? remoteVersion = remoteConfig.GetValueOrDefault("TargetProgram.VersionName");
                string? firstUrl = remoteConfig.GetValueOrDefault("ServerSetting.FirstUrl");

                if (string.IsNullOrEmpty(remoteVersion) || string.IsNullOrEmpty(firstUrl))
                    return false;

                string updateUrl = $"{firstUrl}{remoteVersion}/update_files.xml";

                byte[] updateData = DownloadBytesSync(updateUrl);
                File.WriteAllBytes(updateFilePath, updateData);

                byte[] iniData = DownloadBytesSync(remoteIniUrl);
                File.WriteAllBytes(localIniPath, iniData);

                return false;
            }
            catch (Exception ex)
            {
                HWLogger.ErrorLog($"检测本地可执行文件是否存在失败：{ex.Message}");
                return false;
            }
        }

        private string DownloadStringSync(string url)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var response = client.Send(request);
            response.EnsureSuccessStatusCode();
            return response.Content.ReadAsStringAsync().Result;
        }

        private byte[] DownloadBytesSync(string url)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var response = client.Send(request);
            response.EnsureSuccessStatusCode();
            return response.Content.ReadAsByteArrayAsync().Result;
        }

        private void OnVersionChecked(VersionCheckedEventArgs args)
        {
            VersionChecked?.Invoke(this, args);
        }

        private Dictionary<string, string> ReadIniFile(string path)
        {
            return ParseIniFromString(File.ReadAllText(path));
        }

        private Dictionary<string, string> ParseIniFromString(string content)
        {
            var dict = new Dictionary<string, string>();
            using var reader = new StringReader(content);
            string? line;
            string section = "";

            while ((line = reader.ReadLine()) != null)
            {
                line = line.Trim();
                if (string.IsNullOrEmpty(line) || line.StartsWith(";")) continue;

                if (line.StartsWith("[") && line.EndsWith("]"))
                {
                    section = line.Trim('[', ']');
                    continue;
                }

                var parts = line.Split(new[] { '=' }, 2);
                if (parts.Length == 2)
                {
                    string key = $"{section}.{parts[0].Trim()}";
                    string value = parts[1].Trim();
                    dict[key] = value;
                }
            }

            return dict;
        }
    }
}
